#include <stdio.h>
#include <modbus.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include <sys/msg.h>
#include "shmem.h"
#include "msg_queue_peer.h"
#include "list.h"
#include "cJSON.h"

// 设备类型定义
#define DEV_TYPE_MODBUS 1
#define DEV_TYPE_STM32 0

// 统一数据类型定义
#define DATA_TYPE_BOOL  0
#define DATA_TYPE_INT   1
#define DATA_TYPE_FLOAT 2

// 最大节点数
#define MAX_NODE 128

// 共享内存结构定义
typedef union val_t
{
    int b_val;
    int i_val;
    float f_val;
} val_t;

typedef struct std_node
{
    int key;
    int type;
    int dev_type;
    val_t old_val;
    val_t new_val;
    int ret;
} std_node_t;

// 修复：调整结构体成员顺序以匹配消息队列格式
typedef struct ctl_node
{
    long mtype;
    int value;  // 修复：value在前
    int key;    // 修复：key在后
} control_node_t;

// 设备链表结构
struct list_head head;

struct addr_key
{
    int key;
    int addr;
    int data_type;
    int modbus_type;
    char name[32];
    struct list_head list;
};

modbus_t *ctx = NULL;

// 优化的控制线程函数
void *handler_thread(void *arg)
{
    control_node_t control;
    int msgid = msgget(ftok("topic", 0), 0666 | IPC_CREAT); // 获取消息队列ID
    
    if (msgid == -1) {
        perror("Modbus进程获取消息队列失败");
        return NULL;
    }
    
    while (1)
    {
        int ret = msg_queue_recv("topic", &control, sizeof(control_node_t), 0, IPC_NOWAIT);
        
        if (ret > 0) {
            // 判断key是否属于Modbus设备范围
            if (control.key < MODBUS_KEY_MIN || control.key > MODBUS_KEY_MAX) {
                // 不属于Modbus设备，放回队列
                if (msgsnd(msgid, &control, sizeof(control_node_t) - sizeof(long), IPC_NOWAIT) == -1) {
                    perror("Modbus进程放回消息失败");
                }
                printf("Modbus进程将消息放回队列: key=%d\n", control.key);
                continue;
            }

            // 处理Modbus设备的控制消息
            printf("Modbus进程处理控制: key=%d, value=%d\n", control.key, control.value);

            struct list_head *pos;
            struct addr_key *tmp;
            int found = 0;

            list_for_each(pos, &head)
            {
                tmp = list_entry(pos, struct addr_key, list);

                if (control.key != tmp->key)
                    continue;

                found = 1;

                // Modbus设备控制逻辑（保持原有）
                if (tmp->modbus_type == 1) // 线圈设备
                {
                    int coil_value = (control.value != 0) ? 1 : 0;
                    int base_addr = (tmp->addr > 10000) ? (tmp->addr % 10000) : tmp->addr;
                    int modbus_addr = base_addr - 1;  // 关键地址偏移修正
                    
                    printf("控制线圈: %s, 配置地址: %d, 设备地址: %d, 值: %d\n", 
                           tmp->name, tmp->addr, modbus_addr, coil_value);
                    
                    if (modbus_write_bit(ctx, modbus_addr, coil_value) != 1)
                    {
                        // 失败时尝试寄存器写入模式
                        uint16_t reg_value = coil_value ? 0xFF00 : 0x0000;
                        if (modbus_write_register(ctx, modbus_addr, reg_value) != 1) {
                            fprintf(stderr, "线圈写入失败: %s\n", modbus_strerror(errno));
                        } else {
                            printf("寄存器模式写入成功\n");
                        }
                    }
                }
                else if (tmp->modbus_type == 2) // 寄存器设备
                {
                    int reg_value = (control.value != 0) ? 0xFF00 : 0x0000;
                    int modbus_addr = (tmp->addr > 30000) ? (tmp->addr - 30000) : tmp->addr; // 修正寄存器地址偏移
                    
                    printf("控制寄存器: %s, 配置地址: %d, 设备地址: %d, 值: %d (0x%X)\n", 
                           tmp->name, tmp->addr, modbus_addr, reg_value, reg_value);
                    
                    if (modbus_write_register(ctx, modbus_addr, reg_value) != 1)
                    {
                        fprintf(stderr, "寄存器写入失败: %s\n", modbus_strerror(errno));
                    }
                }
                else
                {
                    printf("忽略未知类型设备: %s (key=%d)\n", tmp->name, control.key);
                }
                break;
            }

            if (!found)
            {
                printf("未找到key=%d的设备\n", control.key);
            }
        }
        usleep(10000); // 降低CPU占用（原100ms可调整为10ms）
    }
    return NULL;
}

std_node_t *find_shm_device_by_key(std_node_t *shm_arr, int count, int key)
{
    for (int i = 0; i < count; i++)
    {
        if (shm_arr[i].key == key)
        {
            return &shm_arr[i];
        }
    }
    return NULL;
}

int map_json_type(int json_type)
{
    switch (json_type)
    {
    case 1: return DATA_TYPE_BOOL;
    case 2: return DATA_TYPE_INT;
    case 3: return DATA_TYPE_FLOAT;
    default: return DATA_TYPE_INT;
    }
}

int get_modbus_type_by_addr(int addr)
{
    if (addr < 10000) return 1;
    return 2;
}

int main(int argc, char const *argv[])
{
    // 1. 创建Modbus TCP实例
    ctx = modbus_new_tcp("192.168.50.127", 502);
    if (!ctx)
    {
        perror("modbus_new_tcp error");
        return -1;
    }

    // 2. 设置从机ID
    int slave = 0x01;
    modbus_set_slave(ctx, slave);

    // 3. 建立连接
    if (modbus_connect(ctx) < 0)
    {
        perror("modbus_connect error");
        modbus_free(ctx);
        return -1;
    }
    printf("Modbus连接成功\n");

    // 4. 设置超时时间
    modbus_set_response_timeout(ctx, 1, 0);

    // 5. 创建共享内存
    struct shm_param para;
    size_t shm_size = sizeof(int) + MAX_NODE * sizeof(std_node_t);

    if (shm_init(&para, "shm_test", shm_size) < 0)
    {
        printf("共享内存初始化失败\n");
        return -1;
    }

    int *p1 = shm_getaddr(&para);
    if (p1 == NULL)
    {
        printf("获取共享内存地址失败\n");
        return -1;
    }
    printf("共享内存地址: %p, 大小: %zu 字节\n", p1, shm_size);

    // 6. 读取JSON配置文件
    FILE *fp = fopen("./node.json", "r");
    if (fp == NULL)
    {
        perror("打开配置文件失败");
        return -1;
    }

    char buf[4096] = {0};
    size_t read_size = fread(buf, 1, 4095, fp);
    if (read_size == 0)
    {
        perror("读取配置文件失败");
        fclose(fp);
        return -1;
    }
    fclose(fp);

    // 7. 解析JSON数据并初始化设备列表
    INIT_LIST_HEAD(&head);

    cJSON *root = cJSON_Parse(buf);
    if (!root)
    {
        printf("JSON解析错误: %s\n", cJSON_GetErrorPtr());
        return -1;
    }

    int *total_devices = p1;
    std_node_t *shm_arr = (std_node_t *)(p1 + 1);

    // 8. 解析Modbus配置
    cJSON *modbus_obj = cJSON_GetObjectItem(root, "modbus");
    if (!modbus_obj)
    {
        printf("未找到modbus节点\n");
        cJSON_Delete(root);
        return -1;
    }

    cJSON *data_array = cJSON_GetObjectItem(modbus_obj, "data");
    if (!data_array)
    {
        printf("未找到modbus data数组\n");
        cJSON_Delete(root);
        return -1;
    }

    int n = cJSON_GetArraySize(data_array);
    printf("解析到 %d 个Modbus设备配置\n", n);

    // 9. 遍历JSON数组，创建设备节点
    for (int i = 0; i < n; i++)
    {
        cJSON *item = cJSON_GetArrayItem(data_array, i);
        if (!item)
            continue;

        cJSON *key_obj = cJSON_GetObjectItem(item, "key");
        cJSON *addr_obj = cJSON_GetObjectItem(item, "addr");
        cJSON *type_obj = cJSON_GetObjectItem(item, "type");
        cJSON *name_obj = cJSON_GetObjectItem(item, "name");

        if (!key_obj || !addr_obj || !type_obj)
        {
            printf("设备配置缺少必要字段，跳过\n");
            continue;
        }

        int key = key_obj->valueint;
        int addr = addr_obj->valueint;
        int json_type = type_obj->valueint;
        int data_type = map_json_type(json_type);
        int modbus_type = get_modbus_type_by_addr(addr);

        struct addr_key *device = malloc(sizeof(struct addr_key));
        if (!device)
        {
            perror("设备内存分配失败");
            continue;
        }

        device->key = key;
        device->addr = addr;
        device->data_type = data_type;
        device->modbus_type = modbus_type;

        if (name_obj && name_obj->valuestring)
        {
            strncpy(device->name, name_obj->valuestring, sizeof(device->name) - 1);
        }
        else
        {
            snprintf(device->name, sizeof(device->name), "Modbus设备_%d", key);
        }

        INIT_LIST_HEAD(&device->list);
        list_add(&device->list, &head);
        printf("添加Modbus设备: %s, key=%d, 地址=%d, 类型=%s\n",
               device->name, key, addr, modbus_type == 1 ? "线圈" : "寄存器");

        std_node_t *shm_device = find_shm_device_by_key(shm_arr, *total_devices, key);
        if (shm_device)
        {
            shm_device->dev_type = DEV_TYPE_MODBUS;
            shm_device->type = data_type;
            printf("更新共享内存设备: key=%d, type=%d\n", key, data_type);
        }
        else
        {
            printf("警告: key=%d的设备在共享内存中未找到\n", key);
        }
    }

    cJSON_Delete(root);

    // 10. 创建处理控制信息的线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, handler_thread, NULL) != 0)
    {
        perror("创建控制线程失败");
        return -1;
    }
    pthread_detach(tid);

    // 11. 主循环：更新Modbus设备数据
    while (1)
    {
        struct list_head *pos;
        list_for_each(pos, &head)
        {
            struct addr_key *device = list_entry(pos, struct addr_key, list);

            std_node_t *shm_device = find_shm_device_by_key(shm_arr, *total_devices, device->key);
            if (!shm_device)
            {
                fprintf(stderr, "错误: key=%d的设备在共享内存中不存在\n", device->key);
                continue;
            }

            int ret = -1;
            val_t old_value = shm_device->new_val;
            val_t new_value = {0};

            switch (device->modbus_type)
            {
            case 1: // 线圈类型
            {
                uint8_t data_bit;
                // ============== 步骤1的修改开始 ==============
                int base_addr = (device->addr > 10000) ? (device->addr % 10000) : device->addr;
                int modbus_addr = base_addr - 1;  // 关键地址偏移修正
                // ============== 步骤1的修改结束 ==============
                
                ret = modbus_read_bits(ctx, modbus_addr, 1, &data_bit);
                if (ret == 1)
                {
                    if (device->data_type == DATA_TYPE_BOOL) {
                        new_value.b_val = (int)data_bit;
                    }
                    else {
                        new_value.i_val = (int)data_bit;
                    }
                    
                    shm_device->old_val = old_value;
                    shm_device->new_val = new_value;
                    shm_device->ret = 0;
                    
                    printf("更新线圈: %s (key=%d) = %d, 设备地址: %d\n",
                           device->name, device->key, data_bit, modbus_addr);
                }
                else
                {
                    shm_device->ret = -1;
                    fprintf(stderr, "读取线圈错误: %s\n", modbus_strerror(errno));
                }
                break;
            }

            case 2: // 寄存器类型
            {
                uint16_t data_regs[2] = {0};
                int regs_to_read = (device->data_type == DATA_TYPE_FLOAT) ? 2 : 1;
                
                // ============== 寄存器地址修正 ==============
                int modbus_addr = (device->addr > 30000) ? (device->addr - 30000) : device->addr;
                if (modbus_addr < 0) modbus_addr = 0;
                
                ret = modbus_read_registers(ctx, modbus_addr, regs_to_read, data_regs);
                if (ret == regs_to_read)
                {
                    switch (device->data_type) {
                        case DATA_TYPE_INT:
                            new_value.i_val = (int)data_regs[0];
                            break;
                        case DATA_TYPE_FLOAT:
                            new_value.f_val = modbus_get_float(data_regs);
                            break;
                        case DATA_TYPE_BOOL:
                            new_value.b_val = (data_regs[0] != 0) ? 1 : 0;
                            break;
                    }
                    
                    shm_device->old_val = old_value;
                    shm_device->new_val = new_value;
                    shm_device->ret = 0;
                    
                    if (device->data_type == DATA_TYPE_FLOAT) {
                        printf("更新寄存器: %s (key=%d) = %.2f, 设备地址: %d\n",
                               device->name, device->key, new_value.f_val, modbus_addr);
                    } else {
                        printf("更新寄存器: %s (key=%d) = %d, 设备地址: %d\n",
                               device->name, device->key, 
                               (device->data_type == DATA_TYPE_BOOL) ? new_value.b_val : new_value.i_val,
                               modbus_addr);
                    }
                }
                else
                {
                    shm_device->ret = -1;
                    fprintf(stderr, "读取寄存器错误: %s\n", modbus_strerror(errno));
                }
                break;
            }
            }
        }
        sleep(1);
    }

    // 清理资源
    struct list_head *pos, *tmp;
    list_for_each_safe(pos, tmp, &head)
    {
        struct addr_key *device = list_entry(pos, struct addr_key, list);
        list_del(pos);
        free(device);
    }

    shm_del(&para);
    modbus_close(ctx);
    modbus_free(ctx);

    return 0;
}